use std::fs;
use std::fs::File;
use std::io::Write;
use std::os::unix::prelude::PermissionsExt;
use std::path::PathBuf;

use glob::PatternError;
use rstest::rstest;

use crate::tests::common::{assert_expected_error, with_cwd};
use crate::tests::fixtures::{
    get_logs_for_current_thread,
    init_logging,
    make_temporary_directory,
    rand_string,
    rand_usize,
    random_tile_type,
    test_data,
    TEMPORARY_DIRECTORY,
};
use crate::tiling::tiles::tile_list::TileList;
use crate::tiling::tiles::{Connectors, Tile, TileType};
use crate::{configuration, Error};

#[allow(dead_code)]
enum TileListError {
    Error(Error),
    ErrorWithVariants(Vec<Error>),
    PatternError(PatternError),
    ConfigError(&'static str),
}

#[test]
fn test_tile_list_new_with_no_config_file_path_no_tile_directory_passed_empty_tile_dir() {
    let current_directory = make_temporary_directory();
    with_cwd(current_directory.path(), || {
        let config = configuration::load(None, None).expect("configuration should be valid");
        let result = TileList::new(config);

        assert_expected_error(
            result,
            Error::ValueError(
                "the list of tiles is empty, it must contain at least one element".to_string(),
            ),
        );
    });
}

#[test]
fn test_tile_list_new_with_no_config_file_path_no_tile_directory_passed_tile_no_perm() {
    // Create a temporary directory.
    let current_directory =
        tempfile::tempdir().expect("the temporary directory could not be created");

    // Create a file within the directory
    let file_path = current_directory.path().join("unreadable.jpg");
    let mut file = File::create(&file_path).expect("failed to create file");
    file.write_all(b"Test data")
        .expect("failed to write to file");

    with_cwd(&current_directory, || {
        // Restrict permissions to make the file unreadable.
        file.set_permissions(fs::Permissions::from_mode(0o000))
            .expect("failed to set permissions");

        let result = TileList::new(
            configuration::load(None, None).expect("the configuration should be valid"),
        );

        assert_expected_error(
            result,
            Error::ValueError(format!(
                "tile type could not be determined from the file {}",
                file_path.display()
            )),
        );
    });

    fs::remove_dir_all(current_directory).expect("could not delete the temporary directory");
}

// Not hard coding test cases here would be too involved, so
// noinspection DuplicatedCode
#[rstest]
// region no config_file_path passed, no tile_directory passed, no tiles in current directory
#[case::no_config_file_path_passed_no_tile_directory_passed_no_tiles_in_current_directory(
    None,
    None,
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![
        format!(
            "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming current \
            working directory {}",
            test_data("empty")
        ),
        "image_tiler::tiling::tiles::tile_list: INFO ⸙ No tiles provided; assuming all files in \
        the tile directory (except ini, json, json5, ron, toml, yaml, or yml files)"
            .to_string(),
    ],
    Some(TileListError::Error(Error::ValueError(
                "the list of tiles is empty, it must contain at least one element".to_string()
    ))),
    test_data("empty"),
)]
// endregion
// region no config_file_path passed, no tile_directory passed, invalid tile in current directory
#[case::no_config_file_path_passed_no_tile_directory_passed_invalid_tile_in_current_directory(
    None,
    None,
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![
        format!(
            "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming current \
            working directory {}",
            test_data("invalid_text_tile")
        ),
        "image_tiler::tiling::tiles::tile_list: INFO ⸙ No tiles provided; assuming all files in \
        the tile directory (except ini, json, json5, ron, toml, yaml, or yml files)"
            .to_string(),
        "image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string(),
        "image_tiler::tiling::tiles::tile_list: INFO ⸙ No tile connectors provided; assuming they \
        all have \
        the same connector on all sides"
            .to_string(),
    ],
    Some(TileListError::Error(Error::ValueError(format!(
            "line lengths of the tile with the name “{}” differ among each other:\n\
            [\n    \"ita\",\n    \"lw\",\n]",
            test_data("invalid_text_tile/tile")
        )
    ))),
    test_data("invalid_text_tile")
)]
// endregion
// region no config_file_path passed, no tile_directory passed, one tile in current directory
#[case::no_config_file_path_passed_no_tile_directory_passed_one_tile_in_current_directory(
    None,
    None,
    TileList {
        tiles: vec![
            Tile::new_text_from_file(
                0,
                test_data("single_text_tile/ink"),
                test_data("single_text_tile/ink"),
                Connectors {
                    north: 2,
                    east: 2,
                    south: 2,
                    west: 2,
                },
                1.,
            ).expect("single_text_tile/ink should be accessible"),
        ],
        horizontal_connector_names: vec![
            "🃟".to_string(),
            "None".to_string(),
            "".to_string(),
        ],
        vertical_connector_names: vec![
            "🃟".to_string(),
            "None".to_string(),
            "".to_string(),
        ],
        tile_type: TileType::Text,
    },
    vec![
        format!(
            "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming current \
            working directory {}",
            test_data("single_text_tile")
        ),
        "image_tiler::tiling::tiles::tile_list: INFO ⸙ No tiles provided; assuming all files in \
        the tile directory (except ini, json, json5, ron, toml, yaml, or yml files)"
            .to_string(),
        "image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string(),
        "image_tiler::tiling::tiles::tile_list: INFO ⸙ No tile connectors provided; assuming they \
        all have \
        the same connector on all sides"
            .to_string(),
    ],
    None,
    test_data("single_text_tile")
)]
// endregion
// region no config_file_path passed, no tile_directory passed, four tiles in current directory
#[case::no_config_file_path_passed_no_tile_directory_passed_four_tiles_in_current_directory(
    None,
    None,
    TileList {
        tiles: vec![
            Tile::new_raster_image_from_file(
                0,
                test_data("four_raster_image_tiles/gray.jpg"),
                test_data("four_raster_image_tiles/gray.jpg"),
                Connectors {
                    north: 2,
                    east: 2,
                    south: 2,
                    west: 2,
                },
                1.,
            ).expect("gray.jpg should be accessible"),
            Tile::new_raster_image_from_file(
                1,
                test_data("four_raster_image_tiles/pixel/blue_pixel.png"),
                test_data("four_raster_image_tiles/pixel/blue_pixel.png"),
                Connectors {
                    north: 2,
                    east: 2,
                    south: 2,
                    west: 2,
                },
                1.,
            ).expect("blue_pixel.png should be accessible"),
            Tile::new_raster_image_from_file(
                2,
                test_data("four_raster_image_tiles/pixel/tile-small.jpg"),
                test_data("four_raster_image_tiles/pixel/tile-small.jpg"),
                Connectors {
                    north: 2,
                    east: 2,
                    south: 2,
                    west: 2,
                },
                1.,
            ).expect("tile-small.jpg should be accessible"),
            Tile::new_raster_image_from_file(
                3,
                test_data("four_raster_image_tiles/some/other/red-white.dds"),
                PathBuf::from(test_data(
                    "four_raster_image_tiles/some/other/red-white.dds",
                )),
                Connectors {
                    north: 2,
                    east: 2,
                    south: 2,
                    west: 2,
                },
                1.,
            ).expect("red-white.dds should be accessible"),
        ],
        horizontal_connector_names: vec![
            "🃟".to_string(),
            "None".to_string(),
            "".to_string(),
        ],
        vertical_connector_names: vec![
            "🃟".to_string(),
            "None".to_string(),
            "".to_string(),
        ],
        tile_type: TileType::Raster,
    },
    vec![
        format!(
            "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming current \
            working directory {}",
            test_data("four_raster_image_tiles")
        ),
        "image_tiler::tiling::tiles::tile_list: INFO ⸙ No tiles provided; assuming all files in \
        the tile directory (except ini, json, json5, ron, toml, yaml, or yml files)"
            .to_string(),
        "image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Raster”".to_string(),
        "image_tiler::tiling::tiles::tile_list: INFO ⸙ No tile connectors provided; assuming they \
        all have the same connector on all sides"
            .to_string(),
    ],
    None,
    test_data("four_raster_image_tiles")
)]
// endregion
// region no config_file_path passed, tile_directory passed, one tile in directory
#[case::no_config_file_path_passed_tile_directory_passed_one_tile_in_directory(
    None,
    Some(test_data("single_text_tile")),
    TileList {
        tiles: vec![
            Tile::new_text_from_file(
                0,
                test_data("single_text_tile/ink"),
                test_data("single_text_tile/ink"),
                Connectors {
                    north: 2,
                    east: 2,
                    south: 2,
                    west: 2,
                },
                1.,
            ).expect("single_text_tile/ink should be accessible"),
        ],
        horizontal_connector_names: vec![
            "🃟".to_string(),
            "None".to_string(),
            "".to_string(),
        ],
        vertical_connector_names: vec![
            "🃟".to_string(),
            "None".to_string(),
            "".to_string(),
        ],
        tile_type: TileType::Text,
    },
    vec![
        "image_tiler::tiling::tiles::tile_list: INFO ⸙ No tiles provided; assuming all files in \
        the tile directory (except ini, json, json5, ron, toml, yaml, or yml files)"
            .to_string(),
        "image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string(),
        "image_tiler::tiling::tiles::tile_list: INFO ⸙ No tile connectors provided; assuming they \
        all have the same connector on all sides"
            .to_string(),
    ],
    None,
    TEMPORARY_DIRECTORY.path().to_string_lossy().to_string()
)]
// endregion
// region no config_file_path passed, invalid tile_directory passed, no tiles
#[case::no_config_file_path_passed_invalid_tile_directory_passed_no_tiles(
    None,
    Some(rand_string(rand_usize(20, 40))),
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![
        "image_tiler::tiling::tiles::tile_list: INFO ⸙ No tiles provided; assuming all files in \
        the tile directory (except ini, json, json5, ron, toml, yaml, or yml files)"
            .to_string(),
    ],
    Some(TileListError::Error(Error::ValueError(
    "the list of tiles is empty, it must contain at least one element".to_string()
    ))),
    test_data("single_text_tile")
)]
// endregion
// region no config_file_path passed, glob error tile_directory passed, no tiles
#[case::no_config_file_path_passed_glob_error_tile_directory_passed_no_tiles(
    None,
    Some("***".to_string()),
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![
        "image_tiler::tiling::tiles::tile_list: INFO ⸙ No tiles provided; assuming all files in \
        the tile directory (except ini, json, json5, ron, toml, yaml, or yml files)"
            .to_string(),
    ],
    Some(
        TileListError::PatternError(PatternError{
            pos: 2,
            msg: "wildcards are either regular `*` or recursive `**`"
        })
    ),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path c0nFiG.toml passed, no tile_directory passed, 0 tiles in current dir
#[case::config_file_path_c0nfig_passed_no_tile_directory_passed_no_tiles_in_current_directory(
    Some(test_data("four_raster_image_tiles/c0nFiG.toml")),
    None,
    TileList {
        tiles: vec![
            Tile::new_raster_image_from_file(
                0,
                test_data("four_raster_image_tiles/gray.jpg"),
                test_data("four_raster_image_tiles/gray.jpg"),
                Connectors {
                    north: 2,
                    east: 2,
                    south: 2,
                    west: 2,
                },
                1.,
            ).expect("gray.jpg should be accessible"),
            Tile::new_raster_image_from_file(
                1,
                test_data("four_raster_image_tiles/pixel/blue_pixel.png"),
                test_data("four_raster_image_tiles/pixel/blue_pixel.png"),
                Connectors {
                    north: 2,
                    east: 2,
                    south: 2,
                    west: 2,
                },
                1.,
            ).expect("blue_pixel.png should be accessible"),
            Tile::new_raster_image_from_file(
                2,
                test_data("four_raster_image_tiles/pixel/tile-small.jpg"),
                test_data("four_raster_image_tiles/pixel/tile-small.jpg"),
                Connectors {
                    north: 2,
                    east: 2,
                    south: 2,
                    west: 2,
                },
                1.,
            ).expect("tile-small.jpg should be accessible"),
            Tile::new_raster_image_from_file(
                3,
                test_data("four_raster_image_tiles/some/other/red-white.dds"),
                PathBuf::from(test_data(
                    "four_raster_image_tiles/some/other/red-white.dds",
                )),
                Connectors {
                    north: 2,
                    east: 2,
                    south: 2,
                    west: 2,
                },
                1.,
            ).expect("red-white.dds should be accessible"),
        ],
        horizontal_connector_names: vec![
            "🃟".to_string(),
            "None".to_string(),
            "".to_string(),
        ],
        vertical_connector_names: vec![
            "🃟".to_string(),
            "None".to_string(),
            "".to_string(),
        ],
        tile_type: TileType::Raster,
    },
    vec![
        format!(
            "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming configuration \
            file directory {}",
            test_data("four_raster_image_tiles")
        ),
        "image_tiler::tiling::tiles::tile_list: INFO ⸙ No tiles provided; assuming all files in \
        the tile directory (except ini, json, json5, ron, toml, yaml, or yml files)"
            .to_string(),
        "image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Raster”".to_string(),
        "image_tiler::tiling::tiles::tile_list: INFO ⸙ No tile connectors provided; assuming they \
        all have the same connector on all sides"
            .to_string(),
    ],
    None,
    test_data("empty")
)]
// endregion
// region config_file_path three_tile_config.yaml passed, no tile_directory passed, three tiles
#[case::config_file_path_three_tile_config_passed_no_tile_directory_passed_three_tiles(
    Some(test_data("three_tile_config.yaml")),
    None,
    TileList {
        tiles: vec![
            Tile::new_raster_image_from_file(
                0,
                "four_raster_image_tiles/gray.jpg".to_string(),
                test_data("four_raster_image_tiles/gray.jpg"),
                Connectors {
                    north: 2,
                    east: 2,
                    south: 3,
                    west: 3,
                },
                978.,
            ).expect("gray.jpg should be accessible"),
            Tile::new_raster_image_from_file(
                1,
                "tile 𝌊".to_string(),
                test_data("four_raster_image_tiles/pixel/tile-small.jpg"),
                Connectors {
                    north: 4,
                    east: 4,
                    south: 3,
                    west: 4,
                },
                0.3,
            ).expect("tile-small.jpg should be accessible"),
            Tile::new_raster_image_from_file(
                2,
                "four_raster_image_tiles/some/other/red-white.dds".to_string(),
                PathBuf::from(test_data(
                    "four_raster_image_tiles/some/other/red-white.dds",
                )),
                Connectors {
                    north: 5,
                    east: 3,
                    south: 6,
                    west: 4,
                },
                1.,
            ).expect("red-white.dds should be accessible"),
        ],
        horizontal_connector_names: vec![
            "🃟".to_string(),
            "None".to_string(),
            "r".to_string(),
            "y".to_string(),
            "l".to_string(),
        ],
        vertical_connector_names: vec![
            "🃟".to_string(),
            "None".to_string(),
            "g".to_string(),
            "a".to_string(),
            "ti".to_string(),
            "t".to_string(),
            "l".to_string(),
        ],
        tile_type: TileType::Raster,
    },
    vec![
        format!(
            "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming configuration \
            file directory {}",
            &test_data("")[..test_data("").len()-1]
        ),
        "image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Raster”".to_string(),
    ],
    None,
    test_data("four_raster_image_tiles")
)]
// endregion
// region config_file_path nil_connector.yaml passed, no tile_directory passed, three tiles
#[case::config_file_path_nil_passed_no_tile_directory_passed_three_tiles(
    Some(test_data("empty/nil_connector.yaml")),
    None,
    TileList {
        tiles: vec![
            Tile::new_text_from_file(
                0,
                "c.yaml".to_string(),
                test_data("empty/c.yaml"),
                Connectors {
                    north: 1,
                    east: 2,
                    south: 2,
                    west: 1,
                },
                4.7,
            ).expect("c.yaml should be accessible"),
            Tile::new_text_from_file(
                1,
                "w.ron".to_string(),
                test_data("empty/w.ron"),
                Connectors {
                    north: 3,
                    east: 3,
                    south: 1,
                    west: 1,
                },
                3.7,
            ).expect("w.ron should be accessible"),
            Tile::new_text_from_file(
                2,
                "peter".to_string(),
                test_data("empty/w.ron"),
                Connectors {
                    north: 1,
                    east: 1,
                    south: 4,
                    west: 4,
                },
                3.0,
            ).expect("w.ron should be accessible"),
        ],
        horizontal_connector_names: vec![
            "🃟".to_string(),
            "None".to_string(),
            "e".to_string(),
            "f".to_string(),
            "z".to_string(),
        ],
        vertical_connector_names: vec![
            "🃟".to_string(),
            "None".to_string(),
            "i".to_string(),
            "8".to_string(),
            "f".to_string(),
        ],
        tile_type: TileType::Text,
    },
    vec![
        format!(
            "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming configuration \
            file directory {}",
            &test_data("empty")
        ),
        "image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string(),
    ],
    None,
    test_data("four_raster_image_tiles")
)]
// endregion
// region config_file_path d.toml passed, no tile_directory passed, three tiles
#[case::config_file_path_d_toml_passed_no_tile_directory_passed_three_tiles(
    Some(test_data("empty/d.toml")),
    None,
    TileList {
        tiles: vec![
            Tile::new_text_from_file(
                0,
                "../single_text_tile/ink".to_string(),
                test_data("single_text_tile/ink"),
                Connectors {
                    north: 2,
                    east: 2,
                    south: 2,
                    west: 2,
                },
                1.0,
            ).expect("single_text_tile/ink should be accessible"),
        ],
        horizontal_connector_names: vec![
            "🃟".to_string(),
            "None".to_string(),
            "".to_string(),
        ],
        vertical_connector_names: vec![
            "🃟".to_string(),
            "None".to_string(),
            "".to_string(),
        ],
        tile_type: TileType::Text,
    },
    vec![
        "image_tiler::tiling::tiles::tile_list: INFO ⸙ No tiles provided; assuming all files in \
        the tile directory (except ini, json, json5, ron, toml, yaml, or yml files)"
            .to_string(),
        "image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string(),
        "image_tiler::tiling::tiles::tile_list: INFO ⸙ No tile connectors provided; assuming they \
        all have the same connector on all sides"
            .to_string(),
    ],
    None,
    test_data("four_raster_image_tiles")
)]
// endregion
// region config_file_path e.ron passed, valid tile_directory passed, no tiles
#[case::config_file_path_e_ron_passed_valid_tile_directory_passed_three_tiles(
    Some(test_data("empty/e.ron")),
    Some(test_data("single_text_tile")),
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![],
    Some(TileListError::Error(Error::ValueError(
        "the list of tiles is empty, it must contain at least one element".to_string()
    ))),
    test_data("four_raster_image_tiles")
)]
// endregion
// region config_file_path invalid f.json passed, no tile_directory passed, one invalid tile
#[case::config_file_path_f_json_passed_no_tile_directory_passed_one_invalid_tile(
    Some(test_data("empty/f.json")),
    None,
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![format!(
        "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming configuration \
        file directory {}",
        test_data("empty")
    )],
    Some(TileListError::Error(Error::ValueError(
        "\
expected a Table (Map), got
Array(
    [
        Value {
            origin: Some(
                \"../../empty/f.json\",
            ),
            kind: Array(
                [
                    Value {
                        origin: Some(
                            \"../../empty/f.json\",
                        ),
                        kind: String(
                            \"path\",
                        ),
                    },
                    Value {
                        origin: Some(
                            \"../../empty/f.json\",
                        ),
                        kind: String(
                            \"four_raster_image_tiles/gray.jpg\",
                        ),
                    },
                ],
            ),
        },
        Value {
            origin: Some(
                \"../../empty/f.json\",
            ),
            kind: Array(
                [
                    Value {
                        origin: Some(
                            \"../../empty/f.json\",
                        ),
                        kind: String(
                            \"connectors\",
                        ),
                    },
                    Value {
                        origin: Some(
                            \"../../empty/f.json\",
                        ),
                        kind: Array(
                            [
                                Value {
                                    origin: Some(
                                        \"../../empty/f.json\",
                                    ),
                                    kind: Array(
                                        [
                                            Value {
                                                origin: Some(
                                                    \"../../empty/f.json\",
                                                ),
                                                kind: String(
                                                    \"north\",
                                                ),
                                            },
                                            Value {
                                                origin: Some(
                                                    \"../../empty/f.json\",
                                                ),
                                                kind: String(
                                                    \"g\",
                                                ),
                                            },
                                        ],
                                    ),
                                },
                                Value {
                                    origin: Some(
                                        \"../../empty/f.json\",
                                    ),
                                    kind: Array(
                                        [
                                            Value {
                                                origin: Some(
                                                    \"../../empty/f.json\",
                                                ),
                                                kind: String(
                                                    \"east\",
                                                ),
                                            },
                                            Value {
                                                origin: Some(
                                                    \"../../empty/f.json\",
                                                ),
                                                kind: String(
                                                    \"r\",
                                                ),
                                            },
                                        ],
                                    ),
                                },
                                Value {
                                    origin: Some(
                                        \"../../empty/f.json\",
                                    ),
                                    kind: Array(
                                        [
                                            Value {
                                                origin: Some(
                                                    \"../../empty/f.json\",
                                                ),
                                                kind: String(
                                                    \"south\",
                                                ),
                                            },
                                            Value {
                                                origin: Some(
                                                    \"../../empty/f.json\",
                                                ),
                                                kind: String(
                                                    \"p\",
                                                ),
                                            },
                                        ],
                                    ),
                                },
                                Value {
                                    origin: Some(
                                        \"../../empty/f.json\",
                                    ),
                                    kind: Array(
                                        [
                                            Value {
                                                origin: Some(
                                                    \"../../empty/f.json\",
                                                ),
                                                kind: String(
                                                    \"west\",
                                                ),
                                            },
                                            Value {
                                                origin: Some(
                                                    \"../../empty/f.json\",
                                                ),
                                                kind: String(
                                                    \"q\",
                                                ),
                                            },
                                        ],
                                    ),
                                },
                            ],
                        ),
                    },
                ],
            ),
        },
        Value {
            origin: Some(
                \"../../empty/f.json\",
            ),
            kind: Array(
                [
                    Value {
                        origin: Some(
                            \"../../empty/f.json\",
                        ),
                        kind: String(
                            \"weight\",
                        ),
                    },
                    Value {
                        origin: Some(
                            \"../../empty/f.json\",
                        ),
                        kind: I64(
                            974,
                        ),
                    },
                ],
            ),
        },
    ],
)".to_string()
    ))),
    test_data("four_raster_image_tiles/pixel")
)]
// endregion
// region config_file_path g.json5 passed, no tile_directory passed, one invalid tile
#[case::config_file_path_g_json5_passed_no_tile_directory_passed_one_invalid_tile(
    Some(test_data("empty/g.json5")),
    None,
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![
        format!(
            "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming configuration \
            file directory {}",
            test_data("empty")
        ),
    ],
    Some(TileListError::Error(Error::ValueError( format!(
            "tile type could not be determined from the file {}",
            test_data("empty/../text_tile_two_rows_three_cols_invalid")
    )))),
    TEMPORARY_DIRECTORY.path().to_string_lossy().to_string()
)]
// endregion
// region config_file_path mar.yml passed, no tile_directory passed, first tile path invalid
#[case::config_file_path_mar_yml_passed_no_tile_directory_passed_first_tile_path_invalid(
    Some(test_data("empty/mar.yml")),
    None,
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![],
    Some(TileListError::Error(Error::ValueError("expected a String, got I64(7)".to_string()))),
    test_data("")
)]
// endregion
// region config_file_path ita.yaml passed, no tile_directory passed, first tile path missing
#[case::config_file_path_ita_yaml_passed_no_tile_directory_passed_first_tile_path_missing(
    Some(test_data("four_raster_image_tiles/some/ita.yaml")),
    None,
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![],
    Some(TileListError::Error(Error::ValueError(
        "\
the first tile is missing the mandatory “path” key:
{
    \"name\": String(
        \"7\",
    ),
}".to_string()
    ))),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path h.yaml passed, valid tile_directory passed, second tile path invalid
#[case::config_file_path_h_yaml_passed_valid_tile_directory_passed_second_tile_path_invalid(
    Some(test_data("empty/h.yaml")),
    Some(".".to_string()),
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec!["image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string()],
    Some(TileListError::Error(Error::ValueError("expected a String, got Array([])".to_string()))),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path i.yaml passed, valid tile_directory passed, tile name invalid
#[case::config_file_path_i_yaml_passed_valid_tile_directory_passed_tile_id_invalid(
    Some(test_data("empty/i.yaml")),
    Some(".".to_string()),
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec!["image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string()],
    Some(TileListError::Error(Error::ValueError("expected a String, got I64(8)".to_string()))),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path k.yaml passed, valid tile_directory passed, tile connectors invalid
#[case::config_file_path_k_yaml_passed_valid_tile_directory_passed_tile_connectors_invalid(
    Some(test_data("empty/k.yaml")),
    Some(".".to_string()),
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec!["image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string()],
    Some(TileListError::Error(Error::ValueError("expected a Table (Map), got I64(8)".to_string()))),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path north.yaml passed, valid tile_directory passed, tile connector north
// invalid
#[case::config_file_path_north_yaml_passed_valid_tile_directory_passed_tile_connector_north_invalid(
    Some(test_data("empty/north.yaml")),
    Some(".".to_string()),
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec!["image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string()],
    Some(TileListError::Error(Error::ValueError("expected a String, got Table({})".to_string()))),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path east.yaml passed, valid tile_directory passed, tile connector east
// invalid
#[case::config_file_path_east_yaml_passed_valid_tile_directory_passed_tile_connector_east_invalid(
    Some(test_data("empty/east.yaml")),
    Some(".".to_string()),
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec!["image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string()],
    Some(TileListError::Error(Error::ValueError("expected a String, got I64(0)".to_string()))),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path south.yaml passed, valid tile_directory passed, tile connector south
// invalid
#[case::config_file_path_south_yaml_passed_valid_tile_directory_passed_tile_connector_south_invalid(
    Some(test_data("empty/south.yaml")),
    Some(".".to_string()),
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec!["image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string()],
    Some(TileListError::Error(Error::ValueError("expected a String, got Array([])".to_string()))),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path west.yaml passed, valid tile_directory passed, tile connector west
// invalid
#[case::config_file_path_west_yaml_passed_valid_tile_directory_passed_tile_connector_west_invalid(
    Some(test_data("empty/west.yaml")),
    Some(".".to_string()),
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec!["image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string()],
    Some(TileListError::Error(Error::ValueError("expected a String, got Float(0.2)".to_string()))),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path weight.yaml passed, valid tile_directory passed, tile weight invalid
#[case::config_file_path_weight_yaml_passed_valid_tile_directory_passed_tile_weight_invalid(
    Some(test_data("empty/weight.yaml")),
    Some(".".to_string()),
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec!["image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string()],
    Some(TileListError::Error(Error::ValueError(
    "\
the “weight” of the tile with the name “ä” has the following error: \
expected a numeric (Float, I64, I128, U64, U128), got Nil"
        .to_string()
    ))),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path invalid_second.yaml passed, no tile_directory passed, second tile invalid
#[case::config_file_path_invalid_second_yaml_passed_no_tile_directory_passed_second_tile_invalid(
    Some(test_data("empty/invalid_second.yaml")),
    None,
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec!["image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string()],
    Some(TileListError::Error(Error::ValueError(
        "\
line lengths of the tile with the name “text_tile_two_rows_three_cols_invalid” differ among each \
other:
[
    \"ita\",
    \"lw\",
]"
        .to_string()
    ))),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path invalid_tiles.yaml passed, no tile_directory passed
#[case::config_file_path_invalid_tiles_yaml_passed_no_tile_directory_passed(
    Some(test_data("empty/invalid_tiles.yaml")),
    None,
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![
        format!(
            "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming configuration \
            file directory {}",
            &test_data("empty")
        ),
        "image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Raster”".to_string()
    ],
    Some(TileListError::Error(Error::ValueError(
        "\
expected a Table (Map), got
Array(
    [
        Value {
            origin: Some(
                \"../empty/invalid_tiles.yaml\",
            ),
            kind: String(
                \"path\",
            ),
        },
        Value {
            origin: Some(
                \"../empty/invalid_tiles.yaml\",
            ),
            kind: String(
                \"../empty/c.yaml\",
            ),
        },
    ],
)"
        .to_string()
    ))),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path no_path.yaml passed, no tile_directory passed
#[case::config_file_path_no_path_yaml_passed_no_tile_directory_passed(
    Some(test_data("empty/no_path.yaml")),
    None,
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![
        format!(
            "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming configuration \
            file directory {}",
            &test_data("empty")
        ),
        "image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string()
    ],
    Some(TileListError::Error(Error::ValueError(
        "\
this tile is missing the mandatory “path” key:
{
    \"name\": String(
        \"gh\",
    ),
}"
        .to_string()
    ))),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path no_connectors.yaml passed, no tile_directory passed
#[case::config_file_path_no_connectors_yaml_passed_no_tile_directory_passed(
    Some(test_data("empty/no_connectors.yaml")),
    None,
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![
        format!(
            "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming configuration \
            file directory {}",
            &test_data("empty")
        ),
        "image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string()
    ],
    Some(TileListError::Error(Error::ValueError(
        "\
this tile is missing the mandatory “connectors” key:
{
    \"name\": String(
        \"d\",
    ),
    \"path\": String(
        \"../empty/k.yaml\",
    ),
}"
        .to_string()
    ))),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path west_missing.yaml passed, no tile_directory passed
#[case::config_file_path_west_missing_yaml_passed_no_tile_directory_passed(
    Some(test_data("empty/west_missing.yaml")),
    None,
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![
        format!(
            "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming configuration \
            file directory {}",
            &test_data("empty")
        ),
        "image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string()
    ],
    Some(TileListError::ErrorWithVariants(vec![
        Error::ValueError(
            "\
the “connectors” section of the tile with the name “d” is missing the \
required “west” connector:
{
    \"connectors\": Table(
        {
            \"east\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"sda\",
                ),
            },
            \"north\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"df\",
                ),
            },
            \"south\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"le\",
                ),
            },
        },
    ),
    \"name\": String(
        \"d\",
    ),
    \"path\": String(
        \"../empty/k.yaml\",
    ),
}"
            .to_string()
        ),
        Error::ValueError(
            "\
the “connectors” section of the tile with the name “d” is missing the \
required “west” connector:
{
    \"connectors\": Table(
        {
            \"east\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"sda\",
                ),
            },
            \"south\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"le\",
                ),
            },
            \"north\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"df\",
                ),
            },
        },
    ),
    \"name\": String(
        \"d\",
    ),
    \"path\": String(
        \"../empty/k.yaml\",
    ),
}"
            .to_string()
        ),
        Error::ValueError(
            "\
the “connectors” section of the tile with the name “d” is missing the \
required “west” connector:
{
    \"connectors\": Table(
        {
            \"north\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"df\",
                ),
            },
            \"east\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"sda\",
                ),
            },
            \"south\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"le\",
                ),
            },
        },
    ),
    \"name\": String(
        \"d\",
    ),
    \"path\": String(
        \"../empty/k.yaml\",
    ),
}"
            .to_string()
        ),
        Error::ValueError(
            "\
the “connectors” section of the tile with the name “d” is missing the \
required “west” connector:
{
    \"connectors\": Table(
        {
            \"north\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"df\",
                ),
            },
            \"south\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"le\",
                ),
            },
            \"east\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"sda\",
                ),
            },
        },
    ),
    \"name\": String(
        \"d\",
    ),
    \"path\": String(
        \"../empty/k.yaml\",
    ),
}"
            .to_string()
        ),
        Error::ValueError(
            "\
the “connectors” section of the tile with the name “d” is missing the \
required “west” connector:
{
    \"connectors\": Table(
        {
            \"south\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"le\",
                ),
            },
            \"east\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"sda\",
                ),
            },
            \"north\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"df\",
                ),
            },
        },
    ),
    \"name\": String(
        \"d\",
    ),
    \"path\": String(
        \"../empty/k.yaml\",
    ),
}"
            .to_string()
        ),
        Error::ValueError(
            "\
the “connectors” section of the tile with the name “d” is missing the \
required “west” connector:
{
    \"connectors\": Table(
        {
            \"south\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"le\",
                ),
            },
            \"north\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"df\",
                ),
            },
            \"east\": Value {
                origin: Some(
                    \"../empty/west_missing.yaml\",
                ),
                kind: String(
                    \"sda\",
                ),
            },
        },
    ),
    \"name\": String(
        \"d\",
    ),
    \"path\": String(
        \"../empty/k.yaml\",
    ),
}"
            .to_string()
        ),
    ])),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path east_south_missing.yaml passed, no tile_directory passed
#[case::config_file_path_east_south_missing_yaml_passed_no_tile_directory_passed(
    Some(test_data("empty/east_south_missing.yaml")),
    None,
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![
        format!(
            "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming configuration \
            file directory {}",
            &test_data("empty")
        ),
        "image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string()
    ],
    Some(TileListError::ErrorWithVariants(vec![
        Error::ValueError(
            "\
the “connectors” section of the tile with the name “first” is missing the \
required “east” connector:
{
    \"connectors\": Table(
        {
            \"north\": Value {
                origin: Some(
                    \"../empty/east_south_missing.yaml\",
                ),
                kind: String(
                    \"+\",
                ),
            },
            \"west\": Value {
                origin: Some(
                    \"../empty/east_south_missing.yaml\",
                ),
                kind: String(
                    \"+\",
                ),
            },
        },
    ),
    \"name\": String(
        \"first\",
    ),
    \"path\": String(
        \"../empty/c.yaml\",
    ),
}"
            .to_string()
        ),
        Error::ValueError(
            "\
the “connectors” section of the tile with the name “first” is missing the \
required “east” connector:
{
    \"connectors\": Table(
        {
            \"west\": Value {
                origin: Some(
                    \"../empty/east_south_missing.yaml\",
                ),
                kind: String(
                    \"+\",
                ),
            },
            \"north\": Value {
                origin: Some(
                    \"../empty/east_south_missing.yaml\",
                ),
                kind: String(
                    \"+\",
                ),
            },
        },
    ),
    \"name\": String(
        \"first\",
    ),
    \"path\": String(
        \"../empty/c.yaml\",
    ),
}"
            .to_string()
        ),
    ])),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path north_south_missing.yaml passed, no tile_directory passed
#[case::config_file_path_north_south_missing_yaml_passed_no_tile_directory_passed(
    Some(test_data("empty/north_south_missing.yaml")),
    None,
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![
        format!(
            "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming configuration \
            file directory {}",
            &test_data("empty")
        ),
        "image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string()
    ],
    Some(TileListError::ErrorWithVariants(vec![
        Error::ValueError(
            "\
the “connectors” section of the tile with the name “../empty/d.toml” is missing the \
required “north” connector:
{
    \"connectors\": Table(
        {
            \"east\": Value {
                origin: Some(
                    \"../empty/north_south_missing.yaml\",
                ),
                kind: String(
                    \"here\",
                ),
            },
            \"west\": Value {
                origin: Some(
                    \"../empty/north_south_missing.yaml\",
                ),
                kind: String(
                    \"there\",
                ),
            },
        },
    ),
    \"name\": String(
        \"../empty/d.toml\",
    ),
    \"path\": String(
        \"../empty/d.toml\",
    ),
}"
            .to_string()
        ),
        Error::ValueError(
            "\
the “connectors” section of the tile with the name “../empty/d.toml” is missing the \
required “north” connector:
{
    \"connectors\": Table(
        {
            \"west\": Value {
                origin: Some(
                    \"../empty/north_south_missing.yaml\",
                ),
                kind: String(
                    \"there\",
                ),
            },
            \"east\": Value {
                origin: Some(
                    \"../empty/north_south_missing.yaml\",
                ),
                kind: String(
                    \"here\",
                ),
            },
        },
    ),
    \"name\": String(
        \"../empty/d.toml\",
    ),
    \"path\": String(
        \"../empty/d.toml\",
    ),
}"
            .to_string()
        ),
    ])),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path south_west_missing.yaml passed, no tile_directory passed
#[case::config_file_path_south_west_missing_yaml_passed_no_tile_directory_passed(
    Some(test_data("empty/south_west_missing.yaml")),
    None,
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![
        format!(
            "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming configuration \
            file directory {}",
            &test_data("empty")
        ),
        "image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Text”".to_string()
    ],
    Some(TileListError::ErrorWithVariants(vec![
        Error::ValueError(
            "\
the “connectors” section of the tile with the name “../empty/d.toml” is missing the \
required “north” connector:
{
    \"connectors\": Table(
        {
            \"south\": Value {
                origin: Some(
                    \"../empty/south_west_missing.yaml\",
                ),
                kind: String(
                    \"here\",
                ),
            },
            \"west\": Value {
                origin: Some(
                    \"../empty/south_west_missing.yaml\",
                ),
                kind: String(
                    \"there\",
                ),
            },
        },
    ),
    \"name\": String(
        \"../empty/d.toml\",
    ),
    \"path\": String(
        \"../empty/d.toml\",
    ),
}"
            .to_string()
        ),
        Error::ValueError(
            "\
the “connectors” section of the tile with the name “../empty/d.toml” is missing the \
required “north” connector:
{
    \"connectors\": Table(
        {
            \"west\": Value {
                origin: Some(
                    \"../empty/south_west_missing.yaml\",
                ),
                kind: String(
                    \"there\",
                ),
            },
            \"south\": Value {
                origin: Some(
                    \"../empty/south_west_missing.yaml\",
                ),
                kind: String(
                    \"here\",
                ),
            },
        },
    ),
    \"name\": String(
        \"../empty/d.toml\",
    ),
    \"path\": String(
        \"../empty/d.toml\",
    ),
}"
            .to_string()
        ),
    ])),
    test_data("single_text_tile")
)]
// endregion
// region config_file_path duplicate_tile.yaml passed, no tile_directory passed
#[case::config_file_path_duplicate_tile_yaml_passed_no_tile_directory_passed(
    Some(test_data("empty/duplicate_tile_config.yaml")),
    None,
    TileList {
        tiles: vec![],
        horizontal_connector_names: vec![],
        vertical_connector_names: vec![],
        tile_type: random_tile_type(),
    },
    vec![
        format!(
            "image_tiler::configuration: INFO ⸙ No tile directory provided; assuming configuration \
            file directory {}",
            &test_data("empty")
        ),
        "image_tiler::tiling::tiles: DEBUG ⸙ Determined tile type “Raster”".to_string(),
    ],
    Some(TileListError::Error(Error::ValueError(
        "there are multiple tiles with the name \
        “../four_raster_image_tiles/some/other/red-white.dds”".to_string()
    ))),
    test_data("four_raster_image_tiles")
)]
// endregion
fn test_tile_list_new(
    #[case] config_file_path: Option<String>,
    #[case] tile_directory: Option<String>,
    #[case] expected_tile_list: TileList,
    #[case] expected_log_messages: Vec<String>,
    #[case] expected_error: Option<TileListError>,
    #[case] cwd: String,
) {
    with_cwd(cwd, || {
        init_logging();
        let tile_list = TileList::new(
            configuration::load(config_file_path.clone(), tile_directory.clone())
                .expect("the configuration should be valid"),
        );

        let log_messages = get_logs_for_current_thread();
        assert_eq!(expected_log_messages, log_messages);

        if let Some(expected_error) = &expected_error {
            match tile_list {
                Ok(_) => panic!("Expected an Err, got Ok"),
                Err(error) => match expected_error {
                    TileListError::Error(expected_error) => {
                        assert_eq!(&error, expected_error)
                    },
                    TileListError::ErrorWithVariants(expected_errors) => {
                        assert!(expected_errors.contains(&error))
                    },
                    TileListError::PatternError(expected_error) => {
                        assert_eq!(expected_error.to_string(), error.to_string())
                    },
                    TileListError::ConfigError(expected_error) => {
                        assert_eq!(*expected_error, error.to_string())
                    },
                },
            }
        } else {
            assert_eq!(tile_list.expect("expected Ok, got Err"), expected_tile_list);
        }
    });
}
